"""
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    created by lane.chang on '04/07/2022'
    comment: 系统日志对象
"""
import os
from dataclasses import dataclass
from logging import StreamHandler, getLogger
from pathlib import Path
from enum import Enum

from colorlog import ColoredFormatter
from concurrent_log_handler import ConcurrentRotatingFileHandler
from typing import Union
from pydantic import BaseModel, Field

from project.core.exception import NotPathError


# 系统日志配置相关
LOG_MAX_BYTES = 100 * 1024 * 1024  # 以此大小轮回覆盖日志文件
LOG_BACKUP_COUNT = 2  # 删除前要保留的日志文件数量


class Colors(Enum):
    """ 颜色列表
    """
    RED = 'red'  # 红
    YELLOW = 'yellow'  # 黄
    GREEN = 'green'  # 绿
    CYAN = 'cyan'  # 灰
    BLUE = 'blue'  # 蓝
    PURPLE = 'purple'  # 紫
    WHITE = 'white'  # 白

    LIGHT_RED = 'light_red'  # 红
    LIGHT_YELLOW = 'light_yellow'  # 黄
    LIGHT_GREEN = 'light_green'  # 绿
    LIGHT_CYAN = 'light_cyan'  # 灰
    LIGHT_BLUE = 'light_blue'  # 蓝
    LIGHT_PURPLE = 'light_purple'  # 紫
    LIGHT_WHITE = 'light_white'  # 白

    BOLD_RED = 'bold_red'  # 红
    BOLD_YELLOW = 'bold_yellow'  # 黄
    BOLD_GREEN = 'bold_green'  # 绿
    BOLD_CYAN = 'bold_cyan'  # 灰
    BOLD_BLUE = 'bold_blue'  # 蓝
    BOLD_PURPLE = 'bold_purple'  # 紫
    BOLD_WHITE = 'bold_white'  # 白


class LoggerColorSetter(BaseModel):
    """
    """
    DEBUG: str = Field(Colors.WHITE.value, title='灰色')
    INFO: str = Field(Colors.GREEN.value, title='白色')
    WARNING: str = Field(Colors.YELLOW.value, title='黄色')
    ERROR: str = Field(Colors.RED.value, title='红')
    CRITICAL: str = Field(Colors.BOLD_RED.value, title='大胆红')


@dataclass
class LogConfig:
    """日志输出配置属性"""

    file_path: str  # 日志文件路径
    file_name: str  # 日志文件名
    level: int  # 日志级别
    pattern: str  # 日志输出格式


class Log:
    """日志类"""

    def __init__(
        self,
        logger_name: str,
        log_config: LogConfig,
        display_console: bool = False
    ):
        """
        :param logger_name:
        :param log_config:
        :param display_console:
        """
        self.logger_name = logger_name

        self.log_config = log_config
        self.__check_file_path()

        self.display_console = display_console

        # 日志文件句柄
        self.handler = None

        # 日志对象
        self.logger = None

        self.__init_logger__()

    def __init_logger__(self):
        """ 日志对象初始化
        :return:
        """
        self.logger = getLogger(self.logger_name)

        file_full_name = (
            f"{self.log_config.file_path}{os.sep}{self.log_config.file_name}")
        self.handler = ConcurrentRotatingFileHandler(
            filename=file_full_name,
            maxBytes=LOG_MAX_BYTES,
            backupCount=LOG_BACKUP_COUNT,
        )

        self.handler.setLevel(self.log_config.level)
        self.logger.addHandler(self.handler)

        # 是否打印到控制台
        if self.display_console:
            stream = StreamHandler()
            stream.setFormatter(ColoredFormatter(self.log_config.pattern))
            stream.setLevel(self.log_config.level)
            self.logger.addHandler(stream)

    def __check_file_path(self):
        """检查日志文件路径的有效性
        :return:
        """
        file_path = self.log_config.file_path
        if not Path(file_path).is_dir():
            raise NotPathError(file_path)

    @classmethod
    def __modify_message(cls, message: str, *args):
        """ 修饰文本
        :param message:
        :param kwargs:
        :return:
        """
        _message = f'[{os.getpid()}]'
        for v in args:
            _message += f' [{v}]'

        _message += f' => {message}'

        return _message

    def debug(self, message: str, *args, font_color=Colors.WHITE.value):
        """输出debug信息
        :param message:
        :param args:
        :param font_color:
        :return:
        """
        formatter = ColoredFormatter(self.log_config.pattern, log_colors=LoggerColorSetter(DEBUG=font_color).dict())
        self.handler.setFormatter(formatter)
        self.logger.debug(self.__class__.__modify_message(message, *args))

    def info(self, message: str, *args, font_color=Colors.GREEN.value):
        """输出info信息
        :param message:
        :param args:
        :param font_color:
        :return:
        """
        formatter = ColoredFormatter(self.log_config.pattern, log_colors=LoggerColorSetter(INFO=font_color).dict())
        self.handler.setFormatter(formatter)
        self.logger.info(self.__class__.__modify_message(message, *args))

    def warning(self, message: str, *args, font_color=Colors.YELLOW.value):
        """输出warning信息
        :param message:
        :param args:
        :param font_color:
        :return:
        """
        formatter = ColoredFormatter(log_colors=LoggerColorSetter(INFO=font_color).dict())
        self.handler.setFormatter(formatter)
        self.logger.warning(self.__class__.__modify_message(message, *args))

    def error(self, message: str, *args, font_color=Colors.RED.value):
        """输出error信息
        :param message:
        :param args:
        :param font_color:
        :return:
        """
        formatter = ColoredFormatter(log_colors=LoggerColorSetter(INFO=font_color).dict())
        self.handler.setFormatter(formatter)
        self.logger.error(self.__class__.__modify_message(message, *args))

    def critical(self, message: Union[str, Exception], *args, exc_info=False, font_color=Colors.BOLD_RED.value):
        """输出critical信息
        :param message: 错误信息
        :param exc_info:
        :param args:
        :param font_color:
        :return:
        """
        formatter = ColoredFormatter(log_colors=LoggerColorSetter(INFO=font_color).dict())
        self.handler.setFormatter(formatter)
        self.logger.critical(self.__class__.__modify_message(message, *args), exc_info=exc_info)
